using System;
using System.Collections.Generic;
using System.Text;
using System.ComponentModel;
using System.Reflection;
using System.Collections;

namespace CodePlex.SpaceBlock.UI
{

    // adapted from http://www.timvw.be/presenting-the-sortablebindinglistt/
    public class SortableBindingList<T> : BindingList<T>
    {
       
        private PropertyDescriptor propertyDescriptor;
        private ListSortDirection listSortDirection;
        private bool isSorted;

   
        public SortableBindingList()
        {
        }

    
        public SortableBindingList(IEnumerable<T> enumerable)
        {
            if (enumerable == null)
            {
                throw new ArgumentNullException("enumerable");
            }

            foreach (T t in enumerable)
            {
                this.Add(t);
            }
        }

      
        protected override bool SupportsSortingCore
        {
            get { return true; }
        }

       
        protected override bool IsSortedCore
        {
            get { return this.isSorted; }
        }

  
        protected override PropertyDescriptor SortPropertyCore
        {
            get { return this.propertyDescriptor; }
        }

     
        protected override ListSortDirection SortDirectionCore
        {
            get { return this.listSortDirection; }
        }


        private Dictionary<string, Comparison<object>> _comparisons = new Dictionary<string, Comparison<object>>();
        public void SetComparison<TProperty>(string name, Comparison<TProperty> comparison)
        {
            _comparisons[name] = delegate(object lhs, object rhs)
            {
                return comparison((TProperty)lhs, (TProperty)rhs);
            };
        }
        protected override void ApplySortCore(PropertyDescriptor prop, ListSortDirection direction)
        {
            List<T> itemsList = this.Items as List<T>;
            itemsList.Sort(delegate(T t1, T t2)
            {
                this.propertyDescriptor = prop;
                this.listSortDirection = direction;
                this.isSorted = true;

                int reverse = direction == ListSortDirection.Ascending ? 1 : -1;

                object value1 = prop.GetValue(t1);
                object value2 = prop.GetValue(t2);

                if (_comparisons.ContainsKey(prop.Name))
                {
                    return reverse * _comparisons[prop.Name](value1, value2);
                }
                else
                {
                    return reverse * Comparer.Default.Compare(value1, value2);
                }
               
            });

            this.OnListChanged(new ListChangedEventArgs(ListChangedType.Reset, -1));
        }

   
        protected override void RemoveSortCore()
        {
            this.isSorted = false;
            this.propertyDescriptor = base.SortPropertyCore;
            this.listSortDirection = base.SortDirectionCore;
        }

      
    }
}
